package com.tmall.testgen.client.genfile.genjava;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

import com.tmall.testgen.client.ClientDataCenter;
import com.tmall.testgen.client.genfile.TotalGenHandler;
import com.tmall.testgen.client.genfile.genjava.bo.ClassInfo;
import com.tmall.testgen.client.genfile.genjava.bo.MethodInfo;
import com.tmall.testgen.client.genfile.genjava.bo.TestClassTemplate;
import com.tmall.testgen.client.genfile.genproject.ProjectGenerator;
import com.tmall.testgen.common.bo.interact.back.InterceptInfo;
import com.tmall.testgen.common.util.StringUtil;

/**
 * @author haojia
 * @date 2014-07-04
 */
public class GenCodeCenter {
	
	
	public static String genTestClassContent(VelocityEngine velocityEngine,TestClassTemplate tmp) throws Exception {
	     
	     
	     Template template = velocityEngine.getTemplate(TotalGenHandler.templateRootPath+"TestGenTemplate.vm");
	     VelocityContext velocityContext = new VelocityContext();
	     String hsfPath=ClientDataCenter.getInstance().getHsfConfig();
	     velocityContext.put("isUseHsf", ClientDataCenter.getInstance().getIsUseHsf());
        if(hsfPath!=null&&hsfPath.length()>0){
            hsfPath=StringUtil.normalizePath(hsfPath);
            hsfPath=hsfPath.replaceAll("/taobao-hsf.sar", "");
            int pos=hsfPath.lastIndexOf("/");
            String hsfRoot=hsfPath.substring(0, pos);
            String version=hsfPath.substring(pos+1);
            velocityContext.put("hsfRoot", hsfRoot);
            velocityContext.put("version", version);
        }
	        
	        
	     velocityContext.put("testClassTemplate", tmp);
	     
	     
	     StringWriter stringWriter = new StringWriter();
	     template.merge(velocityContext, stringWriter);
	     return stringWriter.toString();
	}
	
	
	public static String  genTestClassContent(VelocityEngine velocityEngine ,String testClassName,List<InterceptInfo> toBeGenInfos) throws Exception {
		TestClassTemplate t=getTemplate(testClassName,toBeGenInfos);
		return genTestClassContent(velocityEngine,t);
	} 
	
	public static TestClassTemplate getTemplate(String testClassName,List<InterceptInfo> toBeGenInfos){
		TestClassTemplate template=new TestClassTemplate();
		template.setPackageName(StringUtil.getPackageFromClassName(testClassName));
		template.setTestClassName(StringUtil.getClassSimpleNameFromClassName(testClassName));
		template.setTestClasses(genClassInfo(toBeGenInfos));
		
		
		template.setImports(genImports(toBeGenInfos));
		
		template.getImports().add(ProjectGenerator.commonpackage+".BaseTest");
		template.getImports().add(ProjectGenerator.commonpackage+".bo.MethodSnap");
		template.getImports().add(ProjectGenerator.commonpackage+".util.Comparator");
		template.getImports().add("static org.junit.Assert.assertEquals");
		template.getImports().add("org.junit.Test");
		template.getImports().add("javax.annotation.Resource");
		template.getImports().add("java.util.List");
		template.getImports().add("org.slf4j.Logger");
		template.getImports().add("org.slf4j.LoggerFactory");
		template.getImports().add("org.junit.BeforeClass");
		
		return template;
	}
	
	
	private static Set<String> genImports(List<InterceptInfo> toBeGenInfos){
		Set<String> imports=new HashSet<String>();
		for(InterceptInfo info: toBeGenInfos){
			List<Object> params=(List<Object>) info.getParams();
			//入参
			if(params!=null){
				for(Object param:params){
					if(param==null)
						continue;
					
					String classNamme=param.getClass().getName();
					if(!classNamme.startsWith("java.lang"))
						imports.add(param.getClass().getName());
				}
			}
			//出参
			if(info.getResult()!=null){
				String classNamme=info.getResult().getClass().getName();
				if(!classNamme.startsWith("java.lang"))
					imports.add(info.getResult().getClass().getName());
			}
			
			//测试类
			imports.add(info.getClassName());
		}
		
		
		return imports;
	}
	
	private static List<ClassInfo> genClassInfo(List<InterceptInfo> toBeGenInfos){
	
		Map<String,ClassInfo> map=new HashMap<String,ClassInfo>();
		Map<String,Integer> count=new HashMap<String,Integer>();
		for(InterceptInfo info: toBeGenInfos){
		    if(info.getType()!=InterceptInfo.TYPE_INTERCEPT)
		        continue;
		    
			ClassInfo ci=map.get(info.getClassName());
			if(ci==null){
				ci=new ClassInfo();
				ci.setClassName(info.getClassName());
				ci.setSimpleClassName(info.getClassSimpleName());
				
				if(info.getBeanName()==null){
					ci.setBeanName(StringUtil.firstCharToLower(info.getClassSimpleName()));
					ci.setIsBeanNull(1);
				}else{
					ci.setBeanName(info.getBeanName());
				}
				
				
				List<MethodInfo> methods=new ArrayList<MethodInfo>();
				ci.setMethodInfos(methods);
				map.put(info.getClassName(), ci);
			}
			
			String key=ci.getBeanName()+"_"+info.getMethodName();
			if(count.get(key)==null){
				count.put(key, 0);
			}
		
			MethodInfo m=new MethodInfo();
			if(count.get(key)==0)
				m.setMethodName(info.getClassSimpleName()+"_"+info.getMethodName());
			else
				m.setMethodName(info.getClassSimpleName()+"_"+info.getMethodName()+"_"+count.get(key));
			
			
			m.setMethodContentLines(genMethodContentCode(ci.getSimpleClassName(),ci.getBeanName(),info.getMethodName(),count.get(key),(List<Object>) info.getParams(),info.getResult()));
			m.setExecuteTime(info.getExecuteTime());
			m.setTestDes(info.getTestDes());
			count.put(key, count.get(key)+1);
			ci.getMethodInfos().add(m);
		}
		
		List<ClassInfo> result=new ArrayList<ClassInfo>();
		for( String className:map.keySet()){
			result.add(map.get(className));
		}
		return result;
	}
	
	
	private static List<String> genMethodContentCode(String simpleClassName,String showName,String methodName,int methodKey,List<Object> parammValues,Object resultObj){
		
		
		String resultShow="";
		boolean needGenResult=false;
		boolean isResultNull=false;
		if(resultObj!=null){
//			if(Object2TreeMap.isBasicType(resultObj)){
//				
//				resultShow=resultObj.getClass().getSimpleName()+" expectResult="+resultObj.getClass().getSimpleName()+".valueOf(\""+resultObj+"\");";
//			}else{
				
				resultShow="Object expectResult=snap.getResult();";
			//}
			needGenResult=true;
		}else{
			isResultNull=true;
		}
		
		
		StringBuilder paramShow=new StringBuilder();
		boolean needGenParam=false;
		
		if(!isResultNull){
			paramShow.append("Object result=");
		}
		paramShow.append(showName+"."+methodName+"(");
		for(int i=0;i<parammValues.size();i++){
//			if(Object2TreeMap.isBasicType(parammValues.get(i)))
//				paramShow.append(parammValues.get(i));
//			else{
				if(parammValues.get(i)==null){
					paramShow.append("null");
				}else{
					paramShow.append("("+parammValues.get(i).getClass().getSimpleName()+")params.get("+i+")");
				}
				needGenParam=true;
			//}
			
			if(i!=(parammValues.size()-1)){
				paramShow.append(",");
			}
		}
		paramShow.append(");"+'\n');
		
		
		
		List<String> result=new ArrayList<String>();
		String methodKeyStr="";
		if(methodKey>0){
			methodKeyStr="_"+methodKey;
		}
		if(needGenParam||needGenResult){
			result.add("MethodSnap snap=methodSnap.get(\""+showName+"_"+methodName+methodKeyStr+"\");"+'\n');
			
		}
		//需要生成参数
		if(needGenParam){
			result.add("List<Object> params=snap.getParams();");
		}
		if(needGenResult){
			result.add(resultShow);
		}
		
		StringBuilder logInfo=new StringBuilder();
		if(needGenParam){
		    logInfo.append(methodName+":  ");
			for(int i=0;i<parammValues.size();i++){
				if(i==0){
				    logInfo.append("param["+i+"]=\"+params.get("+i+")  ");
				}else{
				    logInfo.append("+\", param["+i+"]=\"+params.get("+i+")  ");
				}
				
			}
			
		}
		
		if(needGenResult){
		    if(logInfo.length()>0)
		        logInfo.append("+\"");
		    logInfo.append("expectedResult:\"+expectResult");
		}
		
		result.add("");
		result.add("logger.info(\""+logInfo+");");
		result.add("");
		
		result.add(paramShow.toString());
		
		if(!isResultNull){
			result.add("assertEquals(true,comparator.compare(result,expectResult));");
		}
		
		
		return result;
	}



}
